//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Windows.Media;
using OpenLS.Core.Serialization;

namespace OpenLS.Drawing
{
    public class HslColor : ColorBase
    {
        private double hue;
        private double luminance;
        private double saturation;

        public double S
        {
            get { return saturation; }
            set { saturation = value; }
        }

        public double L
        {
            get { return luminance; }
            set { luminance = value; }
        }

        public double H
        {
            get { return hue; }
            set { hue = value; }
        }

        public static implicit operator HslColor(Color color)
        {
            HslColor result = new HslColor();
            double var_R = ((double) color.R/255d); //Where RGB values = 0 � 255
            double var_G = ((double) color.G/255d);
            double var_B = ((double) color.B/255d);

            double var_Min = Math.Min(var_R, Math.Min(var_G, var_B));
            double var_Max = Math.Max(var_R, Math.Max(var_G, var_B));
            double del_Max = var_Max - var_Min; //Delta RGB value

            result.L = (var_Max + var_Min)/2d;

            if (del_Max == 0) //This is a gray, no chroma...
            {
                result.H = 0; //HSL results = 0 � 1
                result.S = 0;
            }
            else //Chromatic data...
            {
                if (result.L < 0.5)
                    result.S = del_Max/(var_Max + var_Min);
                else
                    result.S = del_Max/(2d - var_Max - var_Min);

                double del_R = (((var_Max - var_R)/6d) + (del_Max/2d))/del_Max;
                double del_G = (((var_Max - var_G)/6d) + (del_Max/2d))/del_Max;
                double del_B = (((var_Max - var_B)/6d) + (del_Max/2d))/del_Max;

                if (var_R == var_Max) result.H = del_B - del_G;
                else if (var_G == var_Max) result.H = (1d/3d) + del_R - del_B;
                else if (var_B == var_Max) result.H = (2d/3d) + del_G - del_R;

                if (result.H < 0) result.H += 1d;
                if (result.H > 1) result.H -= 1d;
            }
            //\\Debug.Assert(Color.AreClose(color, (Color)result));
            return result;
        }

        public static implicit operator Color(HslColor color)
        {
            double r, g, b;
            double L = color.L;
            double H = color.H;
            double S = color.S;
            if (S == 0) //HSL values = 0 � 1
            {
                r = L*255d; //RGB results = 0 � 255
                g = L*255d;
                b = L*255d;
            }
            else
            {
                double var_2;
                if (L < 0.5) var_2 = L*(1 + S);
                else var_2 = (L + S) - (S*L);

                double var_1 = 2*L - var_2;

                r = 255*Hue2Rgb(var_1, var_2, H + (1d/3d));
                g = 255*Hue2Rgb(var_1, var_2, H);
                b = 255*Hue2Rgb(var_1, var_2, H - (1d/3d));
            }
            return Color.FromRgb((byte) r, (byte) g, (byte) b);
        }

        private static double Hue2Rgb(double v1, double v2, double vH) //Function Hue_2_RGB
        {
            if (vH < 0) vH += 1;
            if (vH > 1) vH -= 1;
            if ((6d*vH) < 1d) return (v1 + (v2 - v1)*6d*vH);
            if ((2d*vH) < 1d) return (v2);
            if ((3d*vH) < 2d) return (v1 + (v2 - v1)*((2d/3d) - vH)*6d);
            return (v1);
        }

        protected override Color ResolveRawColor(ColorScheme colorScheme)
        {
            return (Color) this;
        }

        internal override void ReadXmlCore(ReadContext context)
        {
            using (var c = context.Read("HslClr"))
            {
                const double factor = 100000;
                L = c.GetDouble("l")/factor;
                S = c.GetDouble("s")/factor;
                H = c.GetDouble("h")/factor;
            }
        }

        internal override void WriteXmlCore(WriteContext context)
        {
            using (WriteContext c = context.Write("HslClr"))
            {
                const double factor = 100000;
                c.SetDouble("l", L*factor);
                c.SetDouble("s", S*factor);
                c.SetDouble("h", H*factor);
            }
        }
    }
}